#ifndef SP_DRIVER_MOUSE_H
#define SP_DRIVER_MOUSE_H

#include <klibc/ctype.h>
#include <system/regs.h>
#include <system/mod.h>


#define MOUSE_CMD_RESET				0xFF 	//Reset 	 The mouse sends ACK (0xFA) and resets.
#define MOUSE_CMD_RESEND			0xFE 	//Resend 	this command makes the mouse sends its second last packet to the host again.
#define MOUSE_CMD_SET_DEFAULTS		0xF6 	//Set Defaults 	The mouse sends ACK (0xFA) and applies default values
#define MOUSE_CMD_DISABLE_DATA_REP	0xF5 	//Disable Data Reporting 	The mouse sends ACK (0xFA) and disable data reporting.
#define MOUSE_CMD_ENABLE_DATA_REP	0xF4 	//Enable Data Reporting 	The mouse sends ACK (0xFA) and enables data reporting
#define MOUSE_CMD_SET_SAMPLE_RATE	0xF3 	//Set Sample Rate 	The mouse sends ACK (0xFA) and waits for the next data, written to the mouse, to be the sample rate
#define MOUSE_CMD_GET_DEV_ID		0xF2 	//Get Device ID 	The mouse sends ACK (0xFA) and sends its ID, though the DATA port
#define MOUSE_CMD_SET_REMOTE_MD		0xF0 	//Set Remote Mode 	The mouse sends ACK (0xFA) and then reset its movement counters, and enters remote mode
#define MOUSE_CMD_SET_WRAP_MD		0xEE 	//Set Wrap Mode 	The mouse sends ACK (0xFA) and then reset its movement counters, and enters warp mode
#define MOUSE_CMD_RESET_WRAP_MD		0xEC 	//Reset Wrap Mode 	The mouse sends ACK, and then enters the last mode, before entering wrap mode, it also resets its movement counters
#define MOUSE_CMD_READ_DATA			0xEB 	//Read Data 	The mouse sends ACK, followed by the first packet, and so on, until It have sent all.
#define MOUSE_CMD_SET_STREAM_MD		0xEA 	//Set Stream Mode 	The mouse sends ACK (0xFA) and then reset its movement counters, and enters reporting mode
#define MOUSE_CMD_STATUS_REQ		0xE9 	//Status Request 	The mouse sends ACK, and sends afterwards the status bytes ( 3 bytes in a row, remember to wait each time for new data)
#define MOUSE_CMD_SET_RES			0xE8 	//Set Resolution 	The mouse sends ACK and waits for the next data, written to the mouse, to be the resolution
#define MOUSE_CMD_SET_SCALE_21		0xE7 	//Set Scaling 2:1 	The mouse sends ACK and set scaling 2:1
#define MOUSE_CMD_SET_SCALE_11		0xE6  	//Set Scaling 1:1 	 The mouse sends ACK and set scaling 1:1 

#define MOUSE_REG_DATA_READ			0x60
#define MOUSE_REG_CMD				0x64


extern module_t mouse_module;


/*
 * Mouse buttom data
 */
typedef struct
{
	uint32_t y_owerflow:1;
	uint32_t x_overflow:1;
	uint32_t y_sign_bit:1;
	uint32_t x_sign_bit:1;
	uint32_t always_1:1;
	uint32_t middle_btn:1;
	uint32_t right_btn:1;
	uint32_t left_btn:1;
} mouse_state_data_t;


/*
 * Mouse data packet
 */
typedef struct
{
	uint8_t state_data;
	uint8_t x_move;
	uint8_t y_move;
} mouse_packet_t;


/*
 * Per la rotellina
 */
typedef struct
{
	uint8_t z_move;	
} mouse_scroll_packet_t;


/*
 * Se abbiamo 2 rotelline
 */
typedef struct
{
	uint32_t always_0:2;
	uint32_t btn_5:1;
	uint32_t btn_4:1;
	uint32_t z3:1;
	uint32_t z2:1;
	uint32_t z1:1;
	uint32_t z0:1;
} mouse_2scroll_packet_t;


/*
 * State packet
 */
typedef struct
{
	uint32_t always_0:1;
	uint32_t mode:1;
	uint32_t enable:1;
	uint32_t scaling:1;
	uint32_t always_9:1;
	uint32_t left_btn:1;
	uint32_t middle_btn:1;
	uint32_t right_btn:1;	

	uint8_t resolution;
	uint8_t sample_rate;	
} mouse_state_packet_t;



mouse_packet_t mouse_buf;

static void mouse_callback(regs_t *);
uint32_t mouse_init();
uint32_t mouse_shut();
uint8_t mouse_wait_write();
uint8_t mouse_wait_read();
void mouse_cmd(uint8_t, uint8_t);
uint32_t mouse_read(uint8_t *, uint32_t, char *);

#endif
